# -*- coding: utf-8 -*-

import json

from django.utils.decorators import method_decorator
from django.utils.encoding import smart_unicode
from django.views.decorators.http import require_GET, require_POST
from django.views.generic import TemplateView

from common.admin import db as user_db
from common.utils import track_logging
from common.utils.api import token_required
from common.utils.decorator import response_wrapper
from common.utils.export import redirect_to_file, gen_filename
from common.utils.tz import utc_to_local_str
from common.withdraw import admin_db as withdraw_db
from common.withdraw import handler as withdraw_handler
from common.withdraw.processor import test_withdraw_channel

_LOGGER = track_logging.getLogger(__name__)


class WithdrawChannelView(TemplateView):
    def get(self, req):
        query_dct = req.GET.dict()
        cond = user_db.get_mchids_filter_by_user(req.user_id)
        if cond and not query_dct.get('mch_id', ''):
            query_dct[u'mch_id'] = cond
        _LOGGER.info('WithdrawChannelView get mchs: %s', query_dct)
        items, total_count = withdraw_db.list_channel(query_dct)

        total_balance = 0.0
        resp_items = []
        for item in items:
            data = item.as_dict()
            data['created_at'] = utc_to_local_str(data['created_at'])
            data['updated_at'] = utc_to_local_str(data['updated_at'])
            resp_items.append(data)
            if item.balance:
                total_balance += float(item.balance)

        return {'list': resp_items, 'page': query_dct.get('$page', 1),
                'size': len(resp_items), 'total_count': total_count, 'total_balance': total_balance}

    def post(self, req):
        param_dct = json.loads(req.body)
        withdraw_db.upsert_channel(param_dct)
        return {}

    def put(self, req):
        return self.post(req)

    @method_decorator(response_wrapper)
    @method_decorator(token_required)
    def dispatch(self, *args, **kwargs):
        return super(WithdrawChannelView, self).dispatch(*args, **kwargs)


class SingleWithdrawChannelView(TemplateView):
    def get(self, req, chn_id):
        channel = withdraw_db.get_channel(id=int(chn_id))
        data = channel.as_dict()
        data['created_at'] = utc_to_local_str(data['created_at'])
        data['updated_at'] = utc_to_local_str(data['updated_at'])
        return data

    def post(self, req, chn_id):
        return self.put(req, chn_id)

    def put(self, req, chn_id):
        query_dct = json.loads(smart_unicode(req.body))
        withdraw_db.upsert_channel(query_dct, int(chn_id))
        return {}

    def patch(self, req, chn_id):
        query_dct = json.loads(smart_unicode(req.body))
        withdraw_db.upsert_channel(query_dct, int(chn_id))
        return {}

    def delete(self, req, chn_id):
        withdraw_db.delete_channel(int(chn_id))
        _LOGGER.info('delete channel: %s, user: %s', chn_id, req.user_id)
        return {}

    @method_decorator(response_wrapper)
    @method_decorator(token_required)
    def dispatch(self, *args, **kwargs):
        return super(SingleWithdrawChannelView, self).dispatch(*args, **kwargs)


class WithdrawOrderView(TemplateView):
    def get(self, req):
        query_dct = req.GET.dict()
        cond = user_db.get_mchids_filter_by_user(req.user_id)
        if cond and not query_dct.get('mch_id', ''):
            query_dct['mch_id'] = cond
        _LOGGER.info('WithdrawOrderView get mchs: %s, ', query_dct)
        export = query_dct.pop('$export', None)
        if export:
            filename = gen_filename('withdraw')
            cn_header = ['id', u'商户订单号', u'支付宝交易流水号', u'创建时间',
                         u'商户ID', u'通道ID', u'通道appid', u'通道名称', u'下分金额',
                         u'下分时间', u'下分状态']
            resp_items = withdraw_db.export_order(query_dct)
            return redirect_to_file(resp_items, cn_header, filename)

        items, total_count = withdraw_db.list_order(query_dct)
        resp_items = []
        for item in items:
            data = item.as_dict()
            data['withdraw_at'] = utc_to_local_str(data['withdraw_at'])
            data['created_at'] = utc_to_local_str(data['created_at'])
            data['updated_at'] = utc_to_local_str(data['updated_at'])
            data['id'] = str(data['id'])
            if export:
                resp_items.append([data.get(x, '-') for x in header])
            else:
                resp_items.append(data)

        overview, chn_ids = withdraw_db.get_order_overview(query_dct)
        chns = withdraw_db.get_channels_in_ids(chn_ids)
        p_info = dict()
        for chn in chns:
            p_info[chn.id] = {
                'name': chn.name,
                'app_id': chn.app_id,
                'payer_name': chn.payer_name,
                'mch_id': chn.mch_id,
            }

        for o in overview:
            chn_id = o['channel_id']
            if chn_id not in p_info:
                continue
            chn_info = p_info[chn_id]
            o.update({
                'channel_name': chn_info['name'],
                'payer_name': chn_info['payer_name'],
                'app_id': chn_info['app_id'],
                'mch_id': chn_info['mch_id']
            })

        return {'list': resp_items, 'page': query_dct.get('$page', 1),
                'overview': overview,
                'size': len(resp_items), 'total_count': total_count}

    def post(self, req):
        param_dct = json.loads(req.body)
        withdraw_db.upsert_order(base=param_dct.get('base'))
        return {}

    @method_decorator(response_wrapper)
    @method_decorator(token_required)
    def dispatch(self, *args, **kwargs):
        return super(WithdrawOrderView, self).dispatch(*args, **kwargs)


class SingleWithdrawOrderView(TemplateView):
    def get(self, req, order_id):
        order = withdraw_db.get_order(id=int(order_id))
        data = order.as_dict()
        data['created_at'] = utc_to_local_str(data['created_at'])
        data['updated_at'] = utc_to_local_str(data['updated_at'])
        return data

    def post(self, req, order_id):
        return self.put(req, order_id)

    def put(self, req, order_id):
        query_dct = json.loads(smart_unicode(req.body))
        withdraw_db.upsert_order(query_dct, int(order_id))
        return {}

    def delete(self, req, order_id):
        withdraw_db.delete_order(int(order_id))
        _LOGGER.info('delete order: %s, user: %s', order_id, req.user_id)
        return {}

    @method_decorator(response_wrapper)
    @method_decorator(token_required)
    def dispatch(self, *args, **kwargs):
        return super(SingleWithdrawOrderView, self).dispatch(*args, **kwargs)


@require_POST
@response_wrapper
@token_required
def fresh(req, order_id):
    order_id = int(order_id)
    order = withdraw_db.get_order(id=order_id)
    if order.status != 0:  # 兑换成功或失败，重新回调
        success, withdraw_order = withdraw_handler.notify_mch(order.id)
        return {
            'success': success
        }
    else:
        # 未兑换，强制兑换
        return {}


@require_POST
@response_wrapper
@token_required
def channel_charge(req, chn_id):
    chn_id = int(chn_id)
    query_dct = req.POST.dict()
    money = query_dct['money']
    withdraw_db.add_channel_balance(chn_id, float(money))
    return {'success': 'success'}


@require_GET
@response_wrapper
def channel_test(req):
    query_dct = req.GET.dict()
    _LOGGER.info('withdraw_channel_test : %s', query_dct)
    cid = int(query_dct['cid'])
    r = test_withdraw_channel(cid)
    _LOGGER.info('withdraw_channel_test rsp: %s', r)
    return {'msg': str(r)}
